#include "board.h"
#include "config.h"
#include "chicken.h"
#include "duck.h"
#include "goose.h"
#include <QSound>
#include <QPainter>
#include<QMessageBox>


Board::Board(QWidget *parent) :QWidget(parent)
{
    resize(boardSize);
    QPalette Pal(palette());
    Pal.setColor(QPalette::Background, Qt::white);
    setAutoFillBackground(true);
    setPalette(Pal);
    setMouseTracking(true);
    firstLine=rect().top()+poultrySize.height()+8;
    secondLine=rect().bottom()-4;
    cartMoved=false;
    cart=new Cart(QPoint((boardSize.width()-cartSize.width())/2,secondLine-4-cartSize.height()));    
    poutryList=new vector<Poultry*>;    
    toPaintList=new queue<Object*>;
    eggList=new queue<Product*>;
    shitList=new queue<Product*>;
    timer=new QTimer();
    speed=4;
    crashedEggs=0;
    catchedShits=0;
    chics=ducs=goos=0;
    isPaused=false;
    catchedEggs=0;
    timeE=0;
    timeLen=5000;
    mousePressed=false;
    Poultry *p=new Chicken(QPoint(6+pos().x(),firstLine-4-poultrySize.height()));    
    poutryList->push_back(p);
    toPaintList->push(p);
    p=new Duck(QPoint(pos().x()+boardSize.width()/2,firstLine-4-poultrySize.height()));
    p->nextProductionTime=clock()+6000;
    poutryList->push_back(p);
    toPaintList->push(p);
    p=new Goose(QPoint(rect().right()-6-poultrySize.width(),firstLine-4-poultrySize.height()));
    p->nextProductionTime=clock()+7000;
    poutryList->push_back(p);
    toPaintList->push(p);
    connect(timer,SIGNAL(timeout()),this,SLOT(timeExecuted()));
    timer->start(150);
    setFocusPolicy(Qt::TabFocus);

}

void Board::paintEvent(QPaintEvent *pe)
{
    QPainter painter(this);
    if(pe->rect()==rect())
    {
        painter.drawLine(rect().x(),firstLine,rect().right(),firstLine);
        painter.drawLine(rect().x(),secondLine,rect().right(),secondLine);
        painter.drawImage(cart->topLeft,cart->getImage());
        for(int i=poutryList->size()-1;i>=0;--i)
            painter.drawImage(poutryList->at(i)->topLeft,poutryList->at(i)->getImage());
        for(int i=eggList->size()-1;i>=0;--i)
        {
            Product *p=eggList->front();
            eggList->pop();
            eggList->push(p);
            painter.drawImage(p->topLeft,p->getImage());
        }
        for(int i=shitList->size()-1;i>=0;--i)
        {
            Product *p=shitList->front();
            shitList->pop();
            shitList->push(p);
            painter.drawImage(p->topLeft,p->getImage());
        }

    }
    if(cartMoved==true)
    {
        painter.drawImage(cart->topLeft,cart->getImage());
        cartMoved=false;
    }

    while(toPaintList->size()>0)
    {
        painter.drawImage(toPaintList->front()->topLeft,toPaintList->front()->getImage());
        toPaintList->pop();
    }
}

void Board::keyPressEvent(QKeyEvent *event)
{    
    if((isPaused==true)&&(event->key()!=Qt::Key_P)) return;
    QRegion region;
    switch(event->key())
    {
        case Qt::Key_P:
            isPaused=!isPaused;
        break;
        case Qt::Key_Left:
            if(cart->topLeft.x()-8<rect().left()) return;
            region=cart->getRegion();
            cart->topLeft.rx()-=8;
            cartMoved=true;
            region+=cart->getRegion();
            repaint(region);            
        break;
        case Qt::Key_Right:
            if(cart->rect().right()+8>rect().right()) return;
            region=cart->getRegion();
            cart->topLeft.rx()+=8;
            cartMoved=true;
            region+=cart->getRegion();
            repaint(region);
        break;
        case Qt::Key_G:
            addChicken();
        break;
        case Qt::Key_V:
            addDuck();
        break;
        case Qt::Key_N:
            addGoose();
        break;
        case Qt::Key_Escape:
        ((QWidget*)(this->parent()))->close();
    }
}

void Board::addChicken()
{
#if OS==WINDOW
    QSound::play(soundsDirectory+"hen.wav");
#endif
    int x=rand()%(boardSize.width()-6-poultrySize.width()-6)+6;
    Poultry *p=new Chicken(QPoint(x+pos().x(),firstLine-4-poultrySize.height()));
    poutryList->push_back(p);
    toPaintList->push(p);
    repaint(p->getRegion());
    ++chics;
}

void Board::addDuck()
{
#if OS==WINDOW
    QSound::play(soundsDirectory+"duck.wav");
#endif
    int x=rand()%(boardSize.width()-6-poultrySize.width()-6)+6;
    Poultry *p=new Duck(QPoint(x+pos().x(),firstLine-4-poultrySize.height()));
    poutryList->push_back(p);
    toPaintList->push(p);
    repaint(p->getRegion());
    ++ducs;
}

void Board::addGoose()
{
#if OS==WINDOW
    QSound::play(soundsDirectory+"goose.wav");
#endif
    int x=rand()%(boardSize.width()-6-poultrySize.width()-6)+6;
    Poultry *p=new Goose(QPoint(x+pos().x(),firstLine-4-poultrySize.height()));
    poutryList->push_back(p);
    toPaintList->push(p);
    repaint(p->getRegion());
    ++goos;
}

void Board::reset()
{

    while(poutryList->size()>0)
    {
        delete poutryList->back();
        poutryList->pop_back();
    }
    while(eggList->size()>0)
    {
        delete eggList->front();
        eggList->pop();
    }
    while(shitList->size()>0)
    {
        delete shitList->front();
        shitList->pop();
    }
    crashedEggs=0;
    catchedShits=0;
    catchedEggs=0;
    timeE=0;
    timeLen=5000;
    isPaused=false;
    speed=4;
    repaint();
    addChicken();
    addDuck();
    addGoose();
    for(int i=0;i<3;++i)
        poutryList->at(i)->nextProductionTime=clock()+5000+i*1000;
    timer->start(150);
}

void Board::mouseMoveEvent(QMouseEvent *even)
{
    if(isPaused==true) return;
    static int limitLeft=cartSize.width()/2+1+pos().x();
    static int limitRight=rect().right()-cartSize.width()/2-1;
    if((even->x()>=limitLeft)&&(even->x()<=limitRight))
    {
        QRegion toCleanRegion=cart->getRegion();
        cart->topLeft.rx()=even->x()-cartSize.width()/2;
        QRegion toPaintRegion=cart->getRegion();
        repaint(toCleanRegion-toPaintRegion);
        toPaintList->push(cart);
        cartMoved=true;
        repaint(toPaintRegion);
    }
}

void Board::mousePressEvent(QMouseEvent *even)
{
    if(isPaused==true) return;
    if(mousePressed==true) return;
    mousePressed=true;
    if(even->y()<firstLine)
    {
        int selected=0,number=chics;
        if(number>ducs)
        {
            selected=1;
            number = ducs;
        }
        if(number>goos)
        {
            selected=2;
            number = goos;
        }
        switch (selected)
        {
            case 0: addChicken();break;
            case 1: addDuck();break;
            case 2: addGoose();break;
        }
    }
}

void Board::mouseReleaseEvent(QMouseEvent *even)
{
    mousePressed=false;
}

void Board::timeExecuted()
{
    if(isPaused==false)
    {
        timeE+=150;
        QRegion toCleanRegion;
        for(int i=eggList->size();i>0;--i)
        {
            Product *p=eggList->front();
            eggList->pop();
            toCleanRegion+=p->getRegion();
            p->topLeft.ry()+=speed;
            if(cart->rect().contains(p->rect().bottomLeft())
                    ||cart->rect().contains(p->rect().bottomRight()))
            {
                delete p;
                ++catchedEggs;
#if OS==WINDOW
                QSound::play(soundsDirectory+"collect.wav");
#endif
                if(catchedEggs%20==0)
                {
                    ++speed;
                    if(catchedShits>0) --catchedShits;
                    if((speed-4)%2==0) timeLen=int(double((timeLen)*85)/100);
                }
            }
            else
                if(p->rect().bottom()<secondLine)
                {
                    eggList->push(p);
                    toCleanRegion-=p->getRegion();
                }
                else
                {
                    delete p;
                    ++crashedEggs;
#if OS==WINDOW
                    QSound::play(soundsDirectory+"crashed.wav");
#endif
                    if(crashedEggs>=3)
                    {
                        timer->stop();
#if OS==WINDOW
                        QSound::play(soundsDirectory+"gameover.wav");
#endif
                        QMessageBox::warning(this,"Game over","Your score: "+QString::number(catchedEggs/((timeE-9000)/5000)));
                        reset();
                        return;
                    }
                }
        }

        for(int i=shitList->size();i>0;--i)
        {
            Product *p=shitList->front();
            shitList->pop();
            toCleanRegion+=p->getRegion();
            p->topLeft.ry()+=speed;
            if(cart->rect().contains(p->rect().bottomLeft())
                    ||cart->rect().contains(p->rect().bottomRight()))
            {
                delete p;
                ++catchedShits;
#if OS==WINDOW
               QSound::play(soundsDirectory+"shit.wav");
#endif
                if(catchedShits>=3)
                {
                    timer->stop();
#if OS==WINDOW
                    QSound::play(soundsDirectory+"gameover.wav");
#endif
                    QMessageBox::warning(this,"Game over","Your score: "+QString::number(catchedEggs/((timeE-9000)/5000)));
                    reset();
                    return;
                }
            }
            else
                if(p->rect().bottom()<secondLine)
                {
                    shitList->push(p);
                    toCleanRegion-=p->getRegion();
                }
                else
                {
                    delete p;
                }
        }

        repaint(toCleanRegion);

        QRegion PaintedRegion;
        for(int i=eggList->size();i>0;--i)
        {
            Product*p=eggList->front();
            eggList->pop();
            eggList->push(p);
            QRegion temp=p->getRegion()-PaintedRegion;
            toPaintList->push(p);
            repaint(temp);
            PaintedRegion+=temp;
        }

        PaintedRegion=QRegion();
        for(int i=shitList->size();i>0;--i)
        {
            Product*p=shitList->front();
            shitList->pop();
            shitList->push(p);
            QRegion temp=p->getRegion()-PaintedRegion;
            toPaintList->push(p);
            repaint(temp);
            PaintedRegion+=temp;
        }
    }

    {
        QRegion toCleanRegion;

        if(isPaused==false)
        for(unsigned i=0;i<poutryList->size();++i)
        {
            int x=(*poutryList)[i]->topLeft.x()+(*poutryList)[i]->direction;
            if((x>=pos().x())&&(x+poultrySize.width()<=rect().right()))
            {
                toCleanRegion+=(*poutryList)[i]->getRegion();
                (*poutryList)[i]->topLeft.rx()=x;
                toCleanRegion-=(*poutryList)[i]->getRegion();
            }
            else (*poutryList)[i]->changeDirection();
        }
        repaint(toCleanRegion);

        QRegion PaintedRegion;
        for(int i=poutryList->size()-1;i>=0;--i)
        {
            Poultry *p=(*poutryList)[i];
            if(isPaused==false)
            {
                toPaintList->push(p);
                QRegion temp=p->getRegion()-PaintedRegion;
                repaint(temp);
                PaintedRegion+=temp;
            }

            if(p->nextProductionTime<=clock())
            {
                if(isPaused==false)
                {
                    Product *pr=p->produce(firstLine,timeLen);
                    if(pr->getType()==Object::EGG)
                        eggList->push(pr);
                    else
                        shitList->push(pr);
                    toPaintList->push(pr);
                    repaint(pr->getRegion());
                }
                else p->resetTime(timeLen);
            }
        }
    }

}

Board::~Board()
{    
    timer->stop();
    while(poutryList->size()>0)
    {
        delete poutryList->back();
        poutryList->pop_back();
    }
    while(eggList->size()>0)
    {
        delete eggList->front();
        eggList->pop();
    }
    while(shitList->size()>0)
    {
        delete shitList->front();
        shitList->pop();
    }
    delete poutryList;
    delete toPaintList;
    delete eggList;
    delete shitList;
    delete cart;
    delete timer;
}
